#include "xlcomm/net/rpc/rpc_client.h"

#include "xlcomm/base/logger.h"

namespace xlcomm {
namespace net {

RpcClient::RpcClient(EventLoop* loop, const InetAddress& server_addr)
    : client_(loop, server_addr, "RpcClient") {
  codec_.set_rpc_cb(std::bind(&RpcClient::OnRpcResult, this, _1, _2));
  client_.set_message_callback(
      std::bind(&RpcCodec::OnMessage, codec_, _1, _2, _3));
}

bool RpcClient::AsyncCall(const std::string& service, const std::string& method,
                          const net::RpcParam& reqParam,
                          const RpcResponseCallback& res_callback) {
  LOG_TRACE << "--method:" << method;
  static int64_t id = 0;
  RpcMeta meta;
  meta.type = RPC_TYPE_REQUEST;
  meta.id = ++id;
  meta.service = service;
  meta.method = method;
  meta.request = reqParam.getMsg();

  pendings_[meta.id] = res_callback;
  codec_.Send(client_.connection(), meta);
  return true;
}

void RpcClient::OnRpcResult(const TcpConnectionPtr& conn, RpcMeta& meta) {
  LOG_TRACE << "----";
  int64_t id = meta.id;
  auto it = pendings_.find(id);
  if (it == pendings_.end()) {
    LOG_WARN << "Can not found pending call";
    return;
  }
  if (meta.type != RPC_TYPE_RESPONSE) {
    LOG_WARN << "It's not RPC_TYPE_RESPONSE";
    return;
  }

  const RpcResponseCallback& cb = it->second;
  RpcParamReader resReader(meta.response);
  cb(resReader, meta.errcode);
}

}  // namespace net
}  // namespace xlcomm